package wikiPhilia_3;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;

import codeanticode.glgraphics.GLGraphics;

import processing.core.PApplet;
import processing.core.PFont;
import processing.core.PVector;
import wpRelations.TsvTable;

public class CopyOfWikiPhilia_006b extends PApplet {
	TsvTable testTable;
	String fileName = "Coby_Miller_stuff3.tsv";
	HashMap<String,WNode> myNodes = new HashMap<String,WNode>();
	ArrayList<WEdge> myEdges = new ArrayList<WEdge>();
	ArrayList<WNode> myNodeArray = new ArrayList<WNode>();
	ArrayList<WNode> myHighlightedNodes = new ArrayList<WNode>();
	ArrayList<WEdge> myHighlightedEdges = new ArrayList<WEdge>();
	ArrayList<WNode> mySelectedNodes = new ArrayList<WNode>();
	ArrayList<WEdge> mySelectedEdges = new ArrayList<WEdge>();
	ArrayList<String> mySelectedNodesTitles = new ArrayList<String>();
	WNode centerNode;
	WArticle centerArticle;
	PFont myFont;
	//String centerArticleTitle = "Coby_Miller";
	public static int maxLinkCount = 0;
	int counter = 0;
	
    float xOff;
    float yOff;
    float zOff = 0;
    boolean setupChanged =false;
    boolean simpleSetup = false;
    float minRadius = 100f;
    float maxRadius = 300f;
	static float yAngle;
	static float xAngle;
	int loadSize = 0;
    
	public void setup() {
		//size(800,800,GLGraphics.GLGRAPHICS);
		//size(800,800,OPENGL);
		size(800,800,P3D);
		testTable = new TsvTable(this, fileName);
		centerArticle = new WArticle(this, "Coby_Miller");
		System.out.println("The table " + fileName + " has " + testTable.getRowCount() + " rows.");
		System.out.println("The table " + fileName + " has " + testTable.data[0].length + " coloumns.");
		noFill();
		noStroke();
		int k = 10000;
		myNodes.put(centerArticle.getTitle(),new WNode(this,centerArticle.getTitle()));
		centerNode = myNodes.get(centerArticle.getTitle());
		centerNode.setType(WNode.TYPE_PERSON_ZERO);
		mySelectedNodes.add(centerNode);
		mySelectedNodesTitles.add(centerNode.getTitle());
		addNodesEdges(testTable, 0, k);
		counter = k;
		myFont = loadFont("data/TheSerifSemiBold-Plain-24.vlw");
		textFont(myFont,12);
		textAlign(CENTER);
		textMode(MODEL);
        float xOff = width/2;
        float yOff = height/2;
        if (simpleSetup) {
			setPositions(200f,0,2);
		} else {
			setPositions(200f,100,101);	
		}
		//setConnectionHighlights(myNodes.get(centerNode.getTitle()));
    	setImportanceHighlights(myNodes.get(centerNode.getTitle()),0.75f);
	}
	
	public void draw() {
		//if (myEdges.size() < 37499) counter++;
		if (frameCount % 30f == 0) {
			addNodesEdges(testTable, counter, counter+loadSize);
			//setPositions(200f,counter-1,counter);
			if (setupChanged || counter+loadSize < testTable.getRowCount()) {
				if (simpleSetup) {
					setPositions(200f,0,2);
				} else {
					//setPositions(200f,100,101);	
					setPositions(200f,counter-1,counter);	
				}
				setupChanged = false;	
				counter += loadSize;
				//setConnectionHighlights(myNodes.get(centerNode.getTitle()));
				//setImportanceHighlights(0.9f);
				setImportanceHighlights(myNodes.get(centerNode.getTitle()),0.75f);
			}
			
			//setHighlightingSelection();
			
		System.out.println("Nodes altogether: " + myNodeArray.size());
		System.out.println("Edges altogether: " + myEdges.size());
		}
		//setPositions(300f,100,101);
		//setPositions(200f,myEdges.size(),myNodeArray.size()+2); //sieht lustig aus
		//setPositions(200f,counter,maxLinkCount); //auch...
		background(0);
		//translate(center.getPos().x,center.getPos().y);
        translate(xOff,yOff,zOff);
		translate(width/2,height/2);
		xAngle = map(mouseY,0,height,0,TWO_PI);
		yAngle = map(mouseX,0,width,0,TWO_PI)+PI;
		rotateX(xAngle);
		rotateY(yAngle);
		//translate(-(width/2-center.getPos().x),-(height/2-center.getPos().y));
		for(int i = 0; i < myNodeArray.size(); i++) {
			myNodeArray.get(i).update();
			myNodeArray.get(i).display();
		}
		for(int i = 0; i < myEdges.size(); i++) {
			myEdges.get(i).display();
		}
		//setPositions(300f,frameCount,5+frameCount);
	}
	
	public void setPositions(float radius, int hC, int vC) {
		int nodeCount = myNodes.size();
		float myInc = 1/(float)(nodeCount);
		centerNode.setPos(new PVector(0,0,0));
		float hCycles = hC;
		float vCycles = vC;
		Set<String> myKeySet = myNodes.keySet();
		ArrayList<String> myKeyList = new ArrayList<String>(myKeySet);
		//String[] myKeyArray = (String[]) list.toArray();
		//Set myKeySet = myNodes.keySet();
		for (int i = 0; i < nodeCount; i++) {
			if (!myKeyList.get(i).equalsIgnoreCase(centerNode.getTitle())) {
				float myRadius = maxRadius - (myNodes.get(myKeyList.get(i)).getLinksCount()/(float)maxLinkCount)*(maxRadius-minRadius);
				float myIncH = myInc*i;
				float myIncV = myInc*i;
				float lambda = TWO_PI*myInc*i*hCycles;
				float beta = TWO_PI*myInc*i*vCycles;
				float x = centerNode.getcPos().x + sin(lambda)*cos(beta)*myRadius;
				float y = centerNode.getcPos().y + sin(beta)*myRadius;
				float z = centerNode.getcPos().z + cos(lambda)*cos(beta)*myRadius;
				myNodes.get(myKeyList.get(i)).setPos(new PVector(x,y,z));
			}
		}
		
	}

	public void addNodesEdges(TsvTable sourceTable, int startIndex, int endIndex) {
		if (myNodes == null) myNodes = new HashMap<String,WNode>();
		if (myEdges == null) myEdges = new ArrayList<WEdge>();
		for (int i = min(sourceTable.getRowCount(),startIndex); i < min(sourceTable.getRowCount(),endIndex); i++) {
			String fromTitle = testTable.getString(i, 0);
			String toTitle = testTable.getString(i, 1);
			String fromType = testTable.getString(i, 2);
			String toType = testTable.getString(i, 3);
			int iFromType = WNode.TYPE_ARTICLE;
			int iToType = WNode.TYPE_ARTICLE;
			if (fromType.equalsIgnoreCase("person")) iFromType = WNode.TYPE_PERSON;
			if (fromType.equalsIgnoreCase("non_person")) iFromType = WNode.TYPE_NON_PERSON;
			if (fromType.equalsIgnoreCase("category")) iFromType = WNode.TYPE_CATEGORY;			
			if (toType.equalsIgnoreCase("person")) iToType = WNode.TYPE_PERSON;
			if (toType.equalsIgnoreCase("non_person")) iToType = WNode.TYPE_NON_PERSON;
			if (toType.equalsIgnoreCase("category")) iToType = WNode.TYPE_CATEGORY;
			WNode fromNode = new WNode(this, fromTitle, iFromType);
			WNode toNode = new WNode(this, toTitle, iToType);
//			if (mySelectedNodes.contains(fromNode)) {
//				fromNode.setState(WNode.STATE_SELECTED);
//				toNode.setState(WNode.STATE_HIGHLIGHTED);
//				if (!myHighlightedNodes.contains(toNode)) myHighlightedNodes.add(toNode);
//			}
//			if (mySelectedNodes.contains(toNode)) {
//				if (!mySelectedNodes.contains(fromNode) && !myHighlightedNodes.contains(fromNode)) {
//					myHighlightedNodes.add(fromNode);
//				}
//				
//			}
			if ( !myNodes.containsKey(fromTitle) && !myNodes.containsKey(toTitle)) {
				myNodes.put(fromTitle,fromNode);
				myNodes.put(toTitle,toNode);
				myNodes.get(fromTitle).incLinks();
				myNodes.get(toTitle).incBacklinks();
				myEdges.add(new WEdge(this,myNodes.get(fromTitle),myNodes.get(toTitle)));
				if (fromNode.getType()==WNode.TYPE_CATEGORY) myEdges.get(myEdges.size()-1).setType(WEdge.TYPE_CONTAINS);
			} else if ( myNodes.containsKey(fromTitle) && !myNodes.containsKey(toTitle)) {
				fromNode.incLinks();
				myNodes.put(toTitle,toNode);
				myEdges.add(new WEdge(this,myNodes.get(fromTitle),myNodes.get(toTitle)));
				myNodes.get(fromTitle).incLinks();
				myNodes.get(toTitle).incBacklinks();
				if (fromNode.getType()==WNode.TYPE_CATEGORY) myEdges.get(myEdges.size()-1).setType(WEdge.TYPE_CONTAINS);	
			} else if (!myNodes.containsKey(fromTitle) && myNodes.containsKey(toTitle)) {
				myNodes.put(fromTitle,fromNode);
				myEdges.add(new WEdge(this,myNodes.get(fromTitle),myNodes.get(toTitle)));
				if (fromNode.getType()==WNode.TYPE_CATEGORY) myEdges.get(myEdges.size()-1).setType(WEdge.TYPE_CONTAINS);
				myNodes.get(fromTitle).incLinks();
				myNodes.get(toTitle).incBacklinks();
			} else {
				//TODO: check if it is a loop
				int in = -1;
				int out = -1;
				
				for (int j = 0; j < myEdges.size(); j++) {
					if(myEdges.get(j).getFromNode().getTitle().equalsIgnoreCase(toTitle) && myEdges.get(j).getToNode().getTitle().equalsIgnoreCase(fromTitle)) in = j;
				}
					if (in > -1 ) {
					myEdges.get(in).setType(WEdge.TYPE_LOOP);
					//if (fromNode.getTitle().equalsIgnoreCase(centerArticle.getTitle()) || toNode.getTitle().equalsIgnoreCase(centerArticle.getTitle())) myEdges.get(myEdges.size()-1).setType(WEdge.TYPE_LOOP_WITH_PZERO);
				} else {
					myNodes.get(fromTitle).incLinks();
					myNodes.get(toTitle).incBacklinks();				
					myEdges.add(new WEdge(this,myNodes.get(fromTitle),myNodes.get(toTitle)));
					if (fromNode.getType()==WNode.TYPE_CATEGORY) myEdges.get(myEdges.size()-1).setType(WEdge.TYPE_CONTAINS);
				}
			}
		}
		myNodeArray = new ArrayList<WNode>(myNodes.values());
		for (int i = 0; i < myNodeArray.size(); i++) {
			if (maxLinkCount < myNodeArray.get(i).getLinksCount()) maxLinkCount =myNodeArray.get(i).getLinksCount();
		}
	}
	
	public void setHighlightingSelection() {
		for (int i = 0; i < mySelectedNodes.size(); i++) {
			mySelectedNodes.get(i).setState(WNode.STATE_SELECTED);
			for (int j = 0; j < myEdges.size(); j++) {
				if (myEdges.get(j).getFromNode().getTitle().equalsIgnoreCase(mySelectedNodes.get(i).getTitle()) && myEdges.get(j).getToNode().getState() != WNode.STATE_SELECTED) {
					myEdges.get(j).getToNode().setState(WNode.STATE_HIGHLIGHTED);
					myEdges.get(j).setState(WEdge.STATE_HIGHLIGHTED);
				}
				if (myEdges.get(j).getToNode().getTitle().equalsIgnoreCase(mySelectedNodes.get(i).getTitle()) && myEdges.get(j).getFromNode().getState() != WNode.STATE_SELECTED) {
					myEdges.get(j).getFromNode().setState(WNode.STATE_HIGHLIGHTED);
					myEdges.get(j).setState(WEdge.STATE_HIGHLIGHTED);
				}
				if (myEdges.get(j).getToNode().getState() == WNode.STATE_SELECTED && myEdges.get(j).getFromNode().getState() == WNode.STATE_SELECTED) {
					myEdges.get(j).setState(WEdge.STATE_SELECTED);
				}
			}
		}
	}
	
	public void setConnectionHighlights(WNode theNode) {
		if (theNode.getState() != WNode.STATE_SELECTED) theNode.setState(WNode.STATE_HIGHLIGHTED);
		for (int j = 0; j < myEdges.size(); j++) {
			if (myEdges.get(j).getFromNode().getTitle().equalsIgnoreCase(theNode.getTitle()) && myEdges.get(j).getToNode().getState() != WNode.STATE_SELECTED) {
				myEdges.get(j).getToNode().setState(WNode.STATE_HIGHLIGHTED);
				myEdges.get(j).setState(WEdge.STATE_HIGHLIGHTED);
			}
			if (myEdges.get(j).getToNode().getTitle().equalsIgnoreCase(theNode.getTitle()) && myEdges.get(j).getFromNode().getState() != WNode.STATE_SELECTED) {
				myEdges.get(j).getFromNode().setState(WNode.STATE_HIGHLIGHTED);
				myEdges.get(j).setState(WEdge.STATE_HIGHLIGHTED);
			}
			if (myEdges.get(j).getToNode().getState() == WNode.STATE_SELECTED && myEdges.get(j).getFromNode().getState() == WNode.STATE_SELECTED) {
				myEdges.get(j).setState(WEdge.STATE_SELECTED);
			}
		}
		
	}
		
	public void setImportanceHighlights(float threshold) {
		for (int j = 0; j < myEdges.size(); j++) {
			if (myEdges.get(j).getFromNode().getLinksCount() >= maxLinkCount*threshold)  {
				myEdges.get(j).getFromNode().setState(WNode.STATE_HIGHLIGHTED);
				//myEdges.get(j).setState(WEdge.STATE_HIGHLIGHTED);
			}
			
			if (myEdges.get(j).getToNode().getLinksCount() >= maxLinkCount*threshold)  {
				myEdges.get(j).getToNode().setState(WNode.STATE_HIGHLIGHTED);
				//myEdges.get(j).setState(WEdge.STATE_HIGHLIGHTED);
			}
			if (myEdges.get(j).getFromNode().getState() == WNode.STATE_HIGHLIGHTED && myEdges.get(j).getToNode().getState() == WNode.STATE_HIGHLIGHTED )  {
				myEdges.get(j).setState(WEdge.STATE_HIGHLIGHTED);
			}
			
		}

	}
	
	public void setImportanceHighlights(WNode theNode,float threshold) {
		for (int j = 0; j < myEdges.size(); j++) {
			if (myEdges.get(j).getFromNode().getTitle().equalsIgnoreCase(theNode.getTitle())) {
				if (myEdges.get(j).getFromNode().getLinksCount() >= maxLinkCount*threshold)  {
					myEdges.get(j).getFromNode().setState(WNode.STATE_HIGHLIGHTED);
					//myEdges.get(j).setState(WEdge.STATE_HIGHLIGHTED);
				}
				
				if (myEdges.get(j).getToNode().getLinksCount() >= maxLinkCount*threshold)  {
					myEdges.get(j).getToNode().setState(WNode.STATE_HIGHLIGHTED);
					//myEdges.get(j).setState(WEdge.STATE_HIGHLIGHTED);
				}
				if (myEdges.get(j).getFromNode().getState() == WNode.STATE_HIGHLIGHTED && myEdges.get(j).getToNode().getState() == WNode.STATE_HIGHLIGHTED )  {
					myEdges.get(j).setState(WEdge.STATE_HIGHLIGHTED);
				}
				
			}
	
			}
				}
	
	public void keyPressed() {
		  if (key == 'w') yOff -= 5;
		  if (key == 's') yOff += 5;
		  if (key == 'a') xOff -= 5;
		  if (key == 'd') xOff += 5;
		  if (key == 'e') zOff += 5;
		  if (key == 'c') zOff -= 5;
		  if (key == 'r') {
			  maxRadius += 10;
				setPositions(200f,100,101);
		  }
		  if (key == 'f') {
			  maxRadius -= 10;
			  if (maxRadius < 0) maxRadius = 0;
				setPositions(200f,100,101);
		  }
		  
		  if (key == 't') {
			  minRadius += 10;
				setPositions(200f,100,101);
		  }
		  
		  if (key == 'g') {
			  minRadius -= 10;
			  if (minRadius < 0) minRadius = 0;
				setPositions(200f,100,101);
		  }
		  
		  if (key == 'y') {
		    simpleSetup = !simpleSetup;
		    setupChanged = true;
		  }
		}
	
	public static void main(String[] args) {
		PApplet.main(new String[] { wikiPhilia.CopyOfWikiPhilia_006b.class.getName() });
	}
	
}